// entity.cpp : contains the definition of the entity component, which all objects must have
// it includes common things like position and entity name
//$Id: Entity.cpp 25 2009-08-21 02:02:10Z brwarner2 $

#include "StdAfx.h"
#include "Entity.h"
#include "Messages.h"
#include "ObjectManager.h"
#include "GameMonkey.h"
#include "gmVector.h"
#include "Area.h"

void CEntity::Init( const ParameterList& params )
{
	//Check if name exists
	if( params.find("name") == params.end() ) m_entityName = "";
	else m_entityName = params.find("name")->second;

	//Check for position
	if( params.find("position") == params.end() ) m_vPos = bug::math::CVector();
	else
	{
		//Parse vector
		std::stringstream str(params.find("position")->second);
		str >> m_vPos.m_x >> m_vPos.m_z;
		m_vPos.m_y = 0.0f;
	}

	//Save parameters
	m_savedParams = params;
}

int CEntity::GMCall( gmThread* a_thread, const std::string &name )
{
	if( name == "GetWorldName" )
	{
		//Check parameters
		GM_CHECK_NUM_PARAMS(0);

		//Create world name variable
		gmVariable worldName = gmVariable( a_thread->GetMachine()->AllocStringObject( m_entityName.c_str() ) );

		//Return it
		a_thread->Push(worldName);
		return GM_OK;
	}
	else if( name == "SetPosition" )
	{
		switch( a_thread->GetNumParams() )
		{
		case 1:
			{
				//Check parameters
				GM_CHECK_TABLE_PARAM( vec, 0 );

				//Create vector
				Position(GetVector(*a_thread->GetMachine(), vec));
				return GM_OK;
			}break;
		case 2:
			{
				//Check parameters
				GM_CHECK_TABLE_PARAM( vec, 0 );
				GM_CHECK_INT_PARAM( ask, 1 );

				//Create vector
				Position(GetVector(*a_thread->GetMachine(), vec), (bool)ask);
				return GM_OK;
			}break;
		}
		return GM_EXCEPTION;
	}
	else if( name == "GetPosition" )
	{
		GM_CHECK_NUM_PARAMS(0);
		
		//Create table
		gmTableObject* v = CreateVector(*a_thread->GetMachine(), m_vPos);

		//Return it
		a_thread->PushTable(v);
		return GM_OK;
	}
	else if( name == "GetArea" )
	{
		GM_CHECK_NUM_PARAMS(0);

		//Get areas user object
		gmUserObject* pArea = GetArea()->GetUser();

		//Return it
		a_thread->PushUser(pArea);
		return GM_OK;
	}
	return GM_EXCEPTION;
}

void CEntity::Message( MessageID message, const boost::any& arg )
{
	switch(message)
	{
	case Messages::Update:
		{
			//Get elapsed time
			float fElapsed = *any_cast<float>(&arg);

			//Call hook
			GetObjectManager()->CallHook(GetObjectID(), "Update", gmVariable(fElapsed));
		}break;
	case Messages::Startup:
		{
			//Create a table
			gmTableObject* params = GetMachine()->AllocTableObject();

			//Add each parameter
			ParameterList::iterator iter = m_savedParams.begin();
			for(; iter != m_savedParams.end(); iter++)
			{
				params->Set(GetMachine(), iter->first.c_str(), gmVariable(GetMachine()->AllocStringObject(iter->second.c_str())));
			}

			//Send away
			GetObjectManager()->CallHook(GetObjectID(), "OnCreate", gmVariable(params));
		}break;
	}
}

void CEntity::RegisterGM( gmMachine* pGM )
{
	//Get object manager
	CObjectManager* pObjects = GetGlobalObjectManager(*pGM);
	pObjects->RegisterMemberFunction(COMPONENT_ID, "GetWorldName");
	pObjects->RegisterMemberFunction(COMPONENT_ID, "SetPosition");
	pObjects->RegisterMemberFunction(COMPONENT_ID, "GetPosition");
	pObjects->RegisterMemberFunction(COMPONENT_ID, "GetArea");
}

void CEntity::Position( const bug::math::CVector& v, bool bAsk )
{
	//Ask for permission before moving
	bug::math::CVector toMove = (v-m_vPos);
	if(bAsk)
		GetObjectManager()->Message(GetObjectID(), Messages::TryMove, &toMove);

	//Set the position
	m_vPos = m_vPos + toMove;
}